package com.demo.jwt;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.demo.constant.TokenConst;
import com.demo.entity.Admin;
import com.demo.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

@Slf4j
public class JwtTokenUtil {

    //创建用户token
    public static String createAdminToken(User user, String action) {
        //加密算法+自己的密钥对数据做一个签名
        Algorithm algorithm = Algorithm.HMAC256(TokenConst.APP_TOKEN_SECRET);
        //jwt.create()创建一个JWTCreator实例来创建一个令牌
        String token = JWT.create()
                .withIssuer("auth0")
                .withClaim("roleId", user.getRoleId())
                .withClaim("action", action)
                .withClaim("userId", user.getUserId())  //存放我们想放在token中的key--value
                .withClaim("userName", user.getUserLoginName())
                .withClaim("userType", user.getUserType())
                .withClaim("workSn", user.getWorkSn())
                .withClaim("userTrueName", user.getUserTrueName())
                .withClaim("userMobile", user.getUserMobile())
                .withSubject("用户")
                .withExpiresAt(new Date(System.currentTimeMillis() + TokenConst.APP_TOKEN_TIME_OUT))  //设置token有效期
                .sign(algorithm);
        //签名+数据一起作为token返回，密钥别人不知道，无法伪造token
        log.info("用户登录创建的token的是----：" + token);
        return token;
    }


    //验证token
    public static DecodedJWT verifyToken(String token) throws Exception {
        log.info("开始验证token，获取到的token值----：" + token);
        if (token == null) {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            throw new Exception("缺少token");
        }
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
        Algorithm algorithm = Algorithm.HMAC256(TokenConst.APP_TOKEN_SECRET);
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();

        DecodedJWT decodedJwt;
        //首先验证token是否过期
        try {
            decodedJwt = jwtVerifier.verify(token);
        } catch (TokenExpiredException e) {
            throw new Exception("token过期");
        }
        //调用解码token方法
        JSONObject decode = decodeTokenPayload(token);
        //用设定的总过期时间--减去当前时间= 得到还剩余过期时间是秒数
        log.info(decode.getInteger("exp") - Integer.parseInt(String.valueOf(System.currentTimeMillis()).substring(0, 10)) + "：---token剩余过期时间");
        //当距离过期时间最近的20分钟执行操作，判断一次decode中是否包含指定的键名（如在在这10分钟之内进行了操作，刷新token//  否则不刷新）
        if (decode.getLong("exp") - Integer.parseInt(String.valueOf(System.currentTimeMillis()).substring(0, 10)) < 1200) {
            String name = "";
            if (decode.containsKey("userId")) {
                name = "userId";
            } else if (decode.containsKey("otherId")) {
                name = "otherId";
            }
            String newtoken = JWT.create()
                    .withIssuer("auth0")
                    .withClaim(name, decode.getInteger(name))  //将新的token存入
                    .withSubject("用户")
                    .withExpiresAt(new Date(System.currentTimeMillis() + TokenConst.APP_TOKEN_TIME_OUT)) //从从新设置过期时间
                    .sign(algorithm);
            response.setHeader("token", newtoken);
        }

        return decodedJwt;
    }

    //解码token
    public static JSONObject decodeTokenPayload(String token) {
        String base64EncodedBody = JWT.decode(token).getPayload();
        Base64 base64Url = new Base64();
        String body = new String(base64Url.decode(base64EncodedBody));
        JSONObject jsonObject = JSON.parseObject(body);
        log.info("解码出来的数据是：" + jsonObject);
        return jsonObject;
    }

    //根据token获取用户ID
    public static Integer decodeTokenUserId(String token) {
        String base64EncodedBody = JWT.decode(token).getPayload();
        Base64 base64Url = new Base64();
        String body = new String(base64Url.decode(base64EncodedBody));
        JSONObject jsonObject = JSON.parseObject(body);
        Integer uid = (Integer) jsonObject.get("userId");
        //log.info("解码出来的用户ID是："+uid);
        return uid;
    }

    //根据token获取用户phone
    public static Integer getUserIdByToken() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String token = request.getHeader("token");
        String[] splitString = token.split("\\.");
        String base64EncodedBody = splitString[1];
        Base64 base64Url = new Base64();
        String body = new String(base64Url.decode(base64EncodedBody));
        JSONObject jsonObject = JSON.parseObject(body);
        return jsonObject.getInteger("phone");
    }

    public static User decodeTokenUser(String token) {
        String base64EncodedBody = JWT.decode(token).getPayload();
        Base64 base64Url = new Base64();
        String body = new String(base64Url.decode(base64EncodedBody));
        JSONObject jsonObject = JSON.parseObject(body);
        User user = new User();
        user.setUserId((Integer) jsonObject.get("userId"));
        user.setWorkSn(jsonObject.get("workSn").toString());
        user.setUserType((Integer) jsonObject.get("userType"));
        user.setUserTrueName(jsonObject.get("userTrueName").toString());
        user.setUserMobile(jsonObject.get("userMobile").toString());
        user.setRoleId((Integer) jsonObject.get("roleId"));
        return user;
    }
}
